home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
mint
/
utils
/
stelm3.lzh
/
STELM
/
ELM.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-12-11
|
20KB
|
857 lines
/* ELM: (c) Jos & Kees Lemmens; Oktober 1993.
This program behaves in a simular way as the UNIX 'elm' program,
which is very popular among UNIX users. (although it has much less
functionality !)
However, the code was written completely by ourselves and we didn't
need much more !!
Unfortunately it can only handle local mail, but it is easy to add
an external program that can handle uucp mail.
Code runs on ATARI (under MINT), on AMIGA 500-4000 (with gcc) and
was also tested on several UNIX platforms.
1.4 : cursor keys on Atari console now recognized;
uucp mailaddresses redirected to OutboudMail function (same
function as for Internet mail)
Any questions or suggestions about this program can be send to:
lemmens@dv.twi.tudelft.nl
*/
/* standard headers */
#include <stdio.h>
#include <stdlib.h> /* getenv, malloc, free and exit */
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <stdarg.h>
#ifdef __MINT__
#include <osbind.h>
#include <termcap.h>
#include <ioctl.h> /* ioctl & tty structs */
#include <fcntl.h> /* O_RDONLY (access) */
#else
#include <curses.h>
#include <term.h>
#include <termios.h>
#include <sys/wait.h>
#endif
/* UNIX headers */
#include <signal.h> /* only for suspend routine */
#include <unistd.h>
/* special headers */
#include "elm.h"
static char *version = "[ELM ST, J&KL; v1.4]";
/* termcap variables */
static char *_tcpent,*_tcpbuf;
static char *CL,*CM,*SO,*SE,*CE,*ME,*MR;
static int LINES,COLS;
#ifdef __MINT__
struct ltchars ltold,ltnew; /* disable suspend */
void ttraw(struct ltchars *ltold,struct ltchars *ltnew)
{
if(ioctl(0, TIOCGLTC, (char *) ltold) < 0)
puts("Can't do ioctl");
ioctl(0, TIOCGLTC, (char *)ltnew);
ltnew->t_suspc = ltnew->t_dsuspc = 0xFF;
ioctl(0, TIOCSLTC, (char *) ltnew);
}
void ttcooked(struct ltchars *ltold)
{
ioctl(0, TIOCSLTC, (char *) ltold);
}
#endif
void InitTermcap(void)
{ char *tmp;
if((tmp=getenv("TERM")) != NULL) /* use UNIX termcap */
{ _tcpent = (char *)malloc(2048); /* must be enough ! */
tgetent(_tcpent,tmp);
_tcpbuf = _tcpent +1024;
CL = tgetstr("cl", &_tcpbuf); CM = tgetstr("cm", &_tcpbuf);
SO = tgetstr("so", &_tcpbuf); SE = tgetstr("se", &_tcpbuf);
CE = tgetstr("ce", &_tcpbuf); ME = tgetstr("me", &_tcpbuf);
MR = tgetstr("mr", &_tcpbuf);
if((tmp=getenv("LINES")) == NULL)
LINES = tgetnum("li");
else
LINES = atoi(tmp);
if((tmp=getenv("COLUMNS")) == NULL)
COLS = tgetnum("co");
else
COLS = atoi(tmp);
}
else /* set acceptable defaults : VT52 code */
{ CL = "\33H\33J"; CM = "\33Y%+ %+ ";
SO = "\33p"; SE = "\33q";
CE = "\33K";
LINES = 24; COLS = 80;
}
}
#ifdef __hpux /* stupid error in HPUX 9.01 headerfile */
int outc(char c)
#else
int outc(int c)
#endif
{ return putchar(c);
}
void Clrscr(void)
{ tputs(CL,1,outc);
}
void Clrtoeol(void)
{ tputs(CE,1,outc);
}
void Gotoxy(int x,int y)
{ tputs(tgoto(CM, x, y),1,outc);
}
void EndTermcap(void)
{ free(_tcpent);
}
void PutStr (char *string,...)
{ va_list ptr;
if(string == NULL)
return;
va_start(ptr,string);
vfprintf(stdout,string,ptr);
fflush(stdout);
va_end(ptr);
}
char GetChar(void)
{ char c;
#ifdef __MINT__
/* this fixes for ATARI cursor keys using scancodes */
static union { long scan; char byte[4]; } ch;
ch.scan=Crawcin();
if (ch.byte[3] == 0)
switch(ch.byte[1])
{ case 'H': return 'k'; /* cursor up */
case 'P': return 'j'; /* cursor down */
/* case 'K': return 'h'; /* cursor left */
/* case 'M': return 'l'; /* cursor right */
}
c = ch.byte[3];
#else
#ifdef __AMIGA__ /* doesn't echo for some reason */
read(fileno(stdin),&c,1);
write(fileno(stdout),&c,1);
#else
read(fileno(stdin),&c,1);
#endif
#endif
return c;
}
char *GetStr(char *string,int size)
{
#ifdef __AMIGA__
/* this implies that input editing (backspacing) is not possible ! */
int count=0;
do
{ *string = GetChar();
if(*string == '\r')
{ *string = '\0';
break;
}
} while(string++,count++ < size);
#else
fgets(string,size,stdin);
#endif
/* todo: try fflush(stdin) on AMIGA, maybe this works !! */
return string;
}
void usage(void)
{ fputs("\nUsage: elm [-f <mailfile>] [-e <editor>]\n",stderr);
exit(1);
}
void PutStatus(char *string,...)
{ va_list ptr;
va_start(ptr,string);
Gotoxy(0,LINES-2);
Clrtoeol();
vfprintf(stdout,string,ptr);
fflush(stdout);
va_end(ptr);
}
void PutHeader(Mbox *M)
{ Gotoxy(5,STARTHEADER);
PutStr("Mailbox '%.30s' with %d messages %s",M->Path,M->Count,version);
}
void PutMenus(void)
{
Gotoxy(4,STARTMENU);
PutStr("m)ail user; f)orward user; r)eply user; $ = reread mailfile; q)uit");
Gotoxy(3,STARTMENU+1);
PutStr("k = move up; j = move down; s)ave to file; d)elete mail; u)ndelete mail");
Gotoxy(4,STARTMENU+2);
PutStr("! = start shell; To read a message, press RETURN");
}
void PutMessage(Mbox *M,int x)
{ int offset = 0;
offset = M->CurMsg /(MSGLISTSIZE) * MSGLISTSIZE;
Gotoxy(0,x-offset+STARTLIST);
PutStr (" %1.1s %.3d %-6.6s %-15.15s (%.3d) %-35.35s",
&M->Msglist[x]->flag, x+1,
M->Msglist[x]->date + 4,
M->Msglist[x]->sender,
M->Msglist[x]->nrlines,
M->Msglist[x]->subject);
}
void PutMessages(Mbox *M)
{ int x;
int offset = 0;
offset = M->CurMsg /(MSGLISTSIZE) * MSGLISTSIZE;
for(x=0;x<MSGLISTSIZE && x+offset<M->Count; x++)
PutMessage(M,offset+x);
while(x<MSGLISTSIZE)
{ Gotoxy(0,x+STARTLIST);
Clrtoeol();
x++;
}
}
void OpenMailbox(Mbox *M)
{ if((M->fd = fopen (ux2dos(M->Path), "r")) == NULL)
{ /* create an empty mailfile */
if((M->fd = fopen (ux2dos(M->Path), "w+")) == NULL)
{ fprintf(stderr,"Can't open mailbox for %s\n",M->User);
exit(1);
}
else
{ PutStatus("Empty mailbox %s created; Press a key ...",
M->Path);
GetChar();
}
}
}
void CloseMailbox(Mbox *M)
{ fclose(M->fd);
}
void RemoveCR(char *ptr)
{ char *tmp;
if((tmp=strchr(ptr,'\n')) != NULL) *tmp = 0;
}
char *EatWhiteSpace(char *ptr)
{ while(*ptr == ' ' || *ptr == '\t') ptr++;
return ptr;
}
void BuildMailList(Mbox *M)
{ int x;
int nrlines=0;
char regel[MAXSTR+1], *tmp1,*tmp2;
OpenMailbox(M);
for(x=0;x < MAXMSG && !feof(M->fd);x++ )
{
/* first search for start of (next) message */
while (strncmp (regel, "From ", 5) && !feof(M->fd) )
{ fgets(regel,MAXSTR,M->fd);
nrlines++;
}
if(feof(M->fd)) break;
M->Msglist[x] = calloc(1,sizeof(Msg));
M->Msglist[x]->start = ftell(M->fd) - strlen(regel) - 1;
M->Msglist[x]->flag = 'N';
M->Msglist[x]->status = 0;
/* assume new msg until proved to be old */
if(x>0) M->Msglist[x-1]->nrlines = nrlines;
nrlines=0; /* start new line count */
if((tmp1 = strchr (regel, ' ')) != NULL) /* sender */
{ tmp1 = EatWhiteSpace(tmp1);
if((tmp2 = strchr (tmp1, ' ')) != NULL) /* date */
{ *tmp2++ = 0; /* fix end of tmp1 */
tmp2 = EatWhiteSpace(tmp2);
strncpy(M->Msglist[x]->date,tmp2,MAXDATE);
}
strncpy(M->Msglist[x]->sender,tmp1,MAXNAME);
}
do
{ fgets (regel,MAXSTR,M->fd);
nrlines++;
if(!strncmp (regel, "Status:",7))
{ if(strchr(regel + 7,'R') != NULL)
M->Msglist[x]->flag = ' ';
M->Msglist[x]->status = 1;
}
else if(!strncmp (regel, "Subject:",8))
{ tmp1 = EatWhiteSpace(regel + 8);
RemoveCR(tmp1);
strncpy(M->Msglist[x]->subject,tmp1,MAXSUBJECT);
}
}while (strncmp (regel, "From ", 5) && !feof(M->fd) );
}
if(x>0) M->Msglist[x-1]->nrlines = nrlines; /* save length for last message */
/* last (extra) record is only used save end of file position */
M->Msglist[x] = calloc(1,sizeof(Msg));
M->Msglist[x]->start = ftell(M->fd);
if(x == 0) /* fix for empty file */
{ M->Msglist[1] = calloc(1,sizeof(Msg));
M->Msglist[1]->start = ftell(M->fd);
}
M->Count = x;
M->CurMsg = 0;
CloseMailbox(M);
}
void SetCurMsg(Mbox *M,int new,int echo)